using System;
using System.Collections.Generic;
using Commons.Injector;

namespace Commons.Injector
{
	public class ConstructorDefinition 
	{
		public Dictionary<int,CtorParamDefinition> parameters;
		public Type[] _cachedTypes;

		public bool varArgs;
		public Type varType;

		public ConstructorDefinition()
		{
			parameters = new Dictionary<int, CtorParamDefinition>();
			_cachedTypes = null;
			varArgs = false;
			varType = typeof(object);
		}

		public Type[] GetConstructorTypes()
		{
			if (_cachedTypes != null)
			{
				return _cachedTypes;
			}

			_cachedTypes = new Type[parameters.Values.Count];

			foreach (CtorParamDefinition paramDef in parameters.Values)
			{
				_cachedTypes[paramDef.index] = paramDef.type;
			}

			return _cachedTypes;
		}

		public object[] GetConstructorValues()
		{
			Type[] types = GetConstructorTypes();

			object[] values = new object[parameters.Count];

			foreach (CtorParamDefinition paramDef in parameters.Values)
			{
				values[paramDef.index] = Convert.ChangeType(paramDef.val, types[paramDef.index]);
			}

			return values;
		}

		public object[] GetConstructorValues(Dictionary<string,object> globalReferences, Dictionary<string,object> localReferences)
		{
			Type[] types = GetConstructorTypes();

			object[] result;
			object[] values;

			if (varArgs)
			{
				values = (object[]) Array.CreateInstance(varType,parameters.Count);
				result = new object[1];
				result[0] = values;
			}
			else
			{
				values = new object[parameters.Count];
				result = values;
			}

			foreach (CtorParamDefinition paramDef in parameters.Values)
			{
				if (paramDef.refId == null)
				{
					values[paramDef.index] = Convert.ChangeType(paramDef.val, types[paramDef.index]);
				}
				else
				{
					values[paramDef.index] = localReferences.ContainsKey(paramDef.refId) ? localReferences[paramDef.refId] : globalReferences[paramDef.refId];
				}
			}

			return result;
		}
	
		public bool IsByValueConstructor()
		{
			foreach (CtorParamDefinition param in parameters.Values)
			{
				if (param.refId != null)
				{
					return false;
				}
			}
			return true;
		}
	}
}
